package com.power.leopard.remote;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

import com.power.leopard.remote.common.domain.InvocationRequest;
import com.power.leopard.remote.provider.domain.InvocationFailureException;

public class ServiceMethodFactory {

	private static final Map<String, ServiceMethodCache> methods = new ConcurrentHashMap<String, ServiceMethodCache>();
	private static final List<String> filterMethods = new ArrayList<String>();

	static {
		Method[] methods = Object.class.getMethods();
		for (Method method : methods) {
			filterMethods.add(method.getName());
		}

		methods = Class.class.getMethods();
		for (Method method : methods) {
			filterMethods.add(method.getName());
		}
	}

	public static void main(String[] args) {
		System.out.println(filterMethods);
	}

	public static void init(String url) {
		getServiceMethodCache(url);
	}

	private static ServiceMethodCache getServiceMethodCache(String url) {
		ServiceMethodCache serviceMethodCache = methods.get(url);
		if (serviceMethodCache == null) {
			Map<String, ProviderConfig<?>> serviceProviders = ServiceProviderFactory.getAllServiceProviders();
			ProviderConfig<?> providerConfig = serviceProviders.get(url);
			if (providerConfig != null) {
				Object service = providerConfig.getService();
				Method[] methodArray = service.getClass().getMethods();

				serviceMethodCache = new ServiceMethodCache(url,service);
				for (Method method : methodArray) {
					String name = method.getName();
					if (!filterMethods.contains(name)) {
						method.setAccessible(true);
						serviceMethodCache.add(new ServiceMethod(method, service));
					}
				}
				methods.put(url, serviceMethodCache);
			}
		}
		return serviceMethodCache;
	}
	
	public static ServiceMethod getMethod(InvocationRequest request) throws InvocationFailureException {
		String serviceName = request.getServiceName();
		String methodName = request.getMethodName();
		
		if(StringUtils.isEmpty(methodName)) {
			throw new IllegalArgumentException("method name is required");
		}
		
		String[] paramClassNames = request.getParamClassName();
		String version = request.getVersion();
		
		String url = ServiceProviderFactory.getServiceUrlWithVersion(serviceName, version);
		ServiceMethodCache serviceMethodCache = getServiceMethodCache(url);
		if(serviceMethodCache == null) {
			serviceMethodCache = getServiceMethodCache(serviceName);
		}
		
		if(serviceMethodCache == null) {
			throw new InvocationFailureException("cannot find service for request:" + request);
		}
		return serviceMethodCache.getMethod(methodName, new ServiceParam(paramClassNames));
	}
}
